package com.paulshiyc.threadpooldemo;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.paulshiyc.threadpooldemo.task.SendBacklogTask;

public class ThreadPoolExecutorTest {

	public static void main(String[] args) {
		/*
		 ThreadPoolExecutor 
		 	corePoolSize :  核心线程数，默认情况下核心线程会一直存活，即使处于闲置状态也不会受存keepAliveTime限制。
		 		除非将allowCoreThreadTimeOut设置为true。
		 	maximumPoolSize: 线程池所能容纳的最大线程数。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时，这个值无效。
		 	keepAliveTime : 非核心线程的闲置超时时间，超过这个时间就会被回收。
		 	unit : 指定keepAliveTime的单位，如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
		 		TimeUnit.NANOSECONDS 纳秒 
		 		TimeUnit.MICROSECONDS 微秒
		 		TimeUnit.MILLISECONDS 毫秒
		 		TimeUnit.SECONDS 秒
		 		TimeUnit.MINUTES 分钟
		 		TimeUnit.HOURS 小时
		 		TimeUnit.DAYS 天
		 	workQueue:线程池中的任务队列. 常用的有三种队列，SynchronousQueue,LinkedBlockingDeque,ArrayBlockingQueue
				 SynchronousQueue
			        SynchronousQueue是无界的，是一种无缓冲的等待队列，但是由于该Queue本身的特性，在某次添加元素后必须等待其他线程取走后才能继续添加；可以认为SynchronousQueue是一个缓存值为1的阻塞队列，但是 isEmpty()方法永远返回是true，remainingCapacity() 方法永远返回是0，remove()和removeAll() 方法永远返回是false，iterator()方法永远返回空，peek()方法永远返回null。
					声明一个SynchronousQueue有两种不同的方式，它们之间有着不太一样的行为。公平模式和非公平模式的区别:如果采用公平模式：SynchronousQueue会采用公平锁，并配合一个FIFO队列来阻塞多余的生产者和消费者，从而体系整体的公平策略；但如果是非公平模式（SynchronousQueue默认）：SynchronousQueue采用非公平锁，同时配合一个LIFO队列来管理多余的生产者和消费者，而后一种模式，如果生产者和消费者的处理速度有差距，则很容易出现饥渴的情况，即可能有某些生产者或者是消费者的数据永远都得不到处理。
			
				 LinkedBlockingQueue
			        LinkedBlockingQueue是无界的，是一个无界缓存的等待队列。
			
					基于链表的阻塞队列，内部维持着一个数据缓冲队列（该队列由链表构成）。当生产者往队列中放入一个数据时，队列会从生产者手中获取数据，并缓存在队列内部，而生产者立即返回；只有当队列缓冲区达到最大值缓存容量时（LinkedBlockingQueue可以通过构造函数指定该值），才会阻塞生产者队列，直到消费者从队列中消费掉一份数据，生产者线程会被唤醒，反之对于消费者这端的处理也基于同样的原理。
			
			        LinkedBlockingQueue之所以能够高效的处理并发数据，还因为其对于生产者端和消费者端分别采用了独立的锁来控制数据同步，这也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据，以此来提高整个队列的并发性能。
			
				ArrayListBlockingQueue
				         ArrayListBlockingQueue是有界的，是一个有界缓存的等待队列。
				         基于数组的阻塞队列，同LinkedBlockingQueue类似，内部维持着一个定长数据缓冲队列（该队列由数组构成）。ArrayBlockingQueue内部还保存着两个整形变量，分别标识着队列的头部和尾部在数组中的位置。
				         ArrayBlockingQueue在生产者放入数据和消费者获取数据，都是共用同一个锁对象，由此也意味着两者无法真正并行运行，这点尤其不同于LinkedBlockingQueue；按照实现原理来分析，ArrayBlockingQueue完全可以采用分离锁，从而实现生产者和消费者操作的完全并行运行。Doug Lea之所以没这样去做，也许是因为ArrayBlockingQueue的数据写入和获取操作已经足够轻巧，以至于引入独立的锁机制，除了给代码带来额外的复杂性外，其在性能上完全占不到任何便宜。 ArrayBlockingQueue和LinkedBlockingQueue间还有一个明显的不同之处在于，前者在插入或删除元素时不会产生或销毁任何额外的对象实例，而后者则会生成一个额外的Node对象。这在长时间内需要高效并发地处理大批量数据的系统中，其对于GC的影响还是存在一定的区别。
				
			         ArrayBlockingQueue和LinkedBlockingQueue是两个最普通、最常用的阻塞队列，一般情况下，处理多线程间的生产者消费者问题，使用这两个类足以。
	 
		 	threadFactory 线程工厂，提供创建新线程的功能。
		 	RejectedExecutionHandler 当线程池中的资源已经全部使用，添加新线程被拒绝时，会调用RejectedExecutionHandler的rejectedExecution方法。
		 	
		 */
		
		//创建任务队列 使用LinkedBlockingQueue 并不指定队列长度 这样适合在不确定任务数得情况下使用
		BlockingQueue<Runnable> lbq = new LinkedBlockingQueue<Runnable>();
		//创建实际业务 即一个任务
		SendBacklogTask s1 = new SendBacklogTask("zhangsan", "张三的待办任务");
		SendBacklogTask s2 = new SendBacklogTask("lisi", "李四的待办任务");
		SendBacklogTask s3 = new SendBacklogTask("wangwu", "王五的待办任务");
		SendBacklogTask s4 = new SendBacklogTask("zhaoliu", "赵六的待办任务");
		SendBacklogTask s5 = new SendBacklogTask("zhuoqi", "卓七的待办任务");
		SendBacklogTask s6 = new SendBacklogTask("qiuba", "丘八的待办任务");
		SendBacklogTask s7 = new SendBacklogTask("yanjiu", "燕九的待办任务");
		SendBacklogTask s8 = new SendBacklogTask("王麻子", "王麻子的待办任务");
		//创建线程池指定核心线程 超时时间等
		ThreadPoolExecutor  threadPoolExecutor = new ThreadPoolExecutor(3, 3, 10,TimeUnit.SECONDS , lbq);
		
		//将任务线程添加到队列中执行
		threadPoolExecutor.execute(s1);
		threadPoolExecutor.execute(s2);
		threadPoolExecutor.execute(s3);
		threadPoolExecutor.execute(s4);
		threadPoolExecutor.execute(s5);
		threadPoolExecutor.execute(s6);
		threadPoolExecutor.execute(s7);
		threadPoolExecutor.execute(s8);
		//关闭线程池
		threadPoolExecutor.shutdown();
		
		/*
		 
		 线程池规则
			线程池的线程执行规则跟任务队列有很大的关系。
			
			一.下面都假设任务队列没有大小限制：
				如果线程数量<=核心线程数量，那么直接启动一个核心线程来执行任务，不会放入队列中。
				如果线程数量>核心线程数，但<=最大线程数，并且任务队列是LinkedBlockingDeque的时候，超过核心线程数量的任务会放在任务队列中排队。
				如果线程数量>核心线程数，但<=最大线程数，并且任务队列是SynchronousQueue的时候，线程池会创建新线程执行任务，这些任务也不会被放在任务队列中。这些线程属于非核心线程，在任务完成后，闲置时间达到了超时时间就会被清除。
				如果线程数量>核心线程数，并且>最大线程数，当任务队列是LinkedBlockingDeque，会将超过核心线程的任务放在任务队列中排队。也就是当任务队列是LinkedBlockingDeque并且没有大小限制时，线程池的最大线程数设置是无效的，他的线程数最多不会超过核心线程数。
				如果线程数量>核心线程数，并且>最大线程数，当任务队列是SynchronousQueue的时候，会因为线程池拒绝添加任务而抛出异常。
			二.任务队列大小有限时
				当LinkedBlockingDeque塞满时，新增的任务会直接创建新线程来执行，当创建的线程数量超过最大线程数量时会抛异常。
				SynchronousQueue没有数量限制。因为他根本不保持这些任务，而是直接交给线程池去执行。当任务数量超过最大线程数时会直接抛异常。
		 */
	}

}
